import { GetMeasurementsDataCommand, ToggleMeasureModeCommand } from "../command/measurements.command"
import { AggregateSubscription, SdkCollection, SdkObservable } from "./observable"
import { ClassFactory, deepDiffers } from "./utils"

const getData = async (e, t) => {
  const o = []
  for (const n of e.groups()) {
    const e = n.info,
      r = t.getFloor(e.floorId)
    for (let t = 1; t < n.count - 1; t++) {
      const a = n.get(t - 1),
        s = n.get(t)
      o.push({
        sid: e.sid,
        label: e.text,
        floor: r.index,
        start: { x: a.x, y: a.y, z: a.z },
        end: { x: s.x, y: s.y, z: s.z }
      })
    }
  }
  return o
}
class MeasurementModeSubFactory {
  CwfMeasuringPhase: any
  constructor(e) {
    this.CwfMeasuringPhase = e
  }
  create(e, t) {
    let o = t.groupCount,
      n = t.phase
    const r = () => {
      const r = t.groupCount,
        a = t.phase
      ;(o === r && n !== this.CwfMeasuringPhase.EDITING) || a !== this.CwfMeasuringPhase.IDLE || (e.onChanged(), (o = r)), (n = a)
    }
    return new AggregateSubscription(t.onPhaseChanged(r), t.onSelectedGroupIndexChanged(r))
  }
}
class MeasurementDataCollection {
  data: {}
  constructor() {
    this.data = {}
  }
  update(e) {
    for (const t of e.groups()) this.createMeasurement(t)
    for (const t in this.data) {
      e.getGroupInfoBySid(t) || delete this.data[t]
    }
  }
  isItemEqual(e, t) {
    return !deepDiffers(this.data[t], e.data[t])
  }
  clear() {
    this.data = {}
  }
  createMeasurement(e) {
    const t = e.info.sid,
      o = this.data[t] || {},
      n = o.points || []
    const eLength = (e, t) => {
      let o = 0
      for (const n of t) {
        const t = e[o] || {}
        t.x = n.x
        t.y = n.y
        t.z = n.z
        e[o] = t
        ++o
      }
      e.length = o
    }
    eLength(n, e)
    o.sid = t
    o.points = n
    this.data[t] = o
  }
}
class MeasurementPhaseSubFactory {
  create(e, t) {
    return t.onChanged(() => e.onChanged())
  }
}
class MeasurementModeObservable {
  _data: { active: boolean }
  constructor() {
    this._data = { active: !1 }
  }
  get data() {
    return this._data
  }
  equals(e) {
    return this._data.active === e.data.active
  }
  copy(e) {
    this._data.active = e.data.active
  }
  update(e) {
    this._data.active = e.modeActive()
  }
}
export default {
  getData: (sdk, allFunc, dependencies) => {
    allFunc.addBinding(GetMeasurementsDataCommand, async () => {
      const [e, t] = await dependencies.getDependencies()
      return getData(e, t)
    })
    sdk.addCommandCreator({ namespace: "Measurements", name: "getData", args: [] }, () => new GetMeasurementsDataCommand())
  },
  data: (sdk, exportOBJ, dependencies) => {
    const data = SdkCollection.create(dependencies, new MeasurementModeSubFactory(exportOBJ.MeasuringPhase), new ClassFactory(MeasurementDataCollection))
    sdk.addCollectionToInterface({ namespace: "Measurements", name: "data" }, data)
  },
  mode: (sdk, dependencies) => {
    const observable = SdkObservable.create(dependencies, new MeasurementPhaseSubFactory(), new ClassFactory(MeasurementModeObservable))
    sdk.addObservableToInterface({ namespace: "Measurements", name: "mode" }, observable)
  },
  toggleMode: (sdk, exportOBJ, allFunc) => {
    allFunc.addBinding(ToggleMeasureModeCommand, async e => allFunc.issueCommand(new exportOBJ.ToggleToolCommand(exportOBJ.Tools.MEASUREMENTS, e.active))),
      sdk.addCommandCreator({ namespace: "Measurements", name: "toggleMode", args: ["active"] }, e => new ToggleMeasureModeCommand(e.active))
  }
}
